/* @(#)AbstractTreeViewAdapter.java
** 
** Copyright (C) 2012 by Steven D. Stamps
**
**             Trademarks & Copyrights
** Flywheel Management Science(TM), Flywheel Management Model(TM),
** Flywheel Story Editor(TM) and FlywheelMS(TM) are exclusive trademarks
** of Steven D. Stamps and may only be used freely for the purpose of
** identifying the unforked version of this software.  Subsequent forks
** may not use these trademarks.  All other rights are reserved.
**
** DecKanGL (Decorated Kanban Glyph Language) and TribKn (Tribal Knowledge)
** are also exclusive trademarks of Steven D. Stamps.  These may be used
** freely within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** gConGUI (game Controller Graphical User Interface) is an exclusive
** trademark of Steven D. Stamps.  This trademark may be used freely
** within the unforked FlywheelMS application and documentation.
** All other rights are reserved.
**
** Trademark information is available at
** <http://www.flywheelms.com/trademarks>
**
** Flywheel Management Science(TM) is a copyrighted body of management
** metaphors, governance processes, and leadership techniques that is
** owned by Steven D. Stamps.  These copyrighted materials may be freely
** used, without alteration, by the community (users and developers)
** surrounding this GPL3-licensed software.  Additional copyright
** information is available at <http://www.flywheelms.org/copyrights>
**
**              GPL3 Software License
** This program is free software: you can use it, redistribute it and/or
** modify it under the terms of the GNU General Public License, version 3,
** as published by the Free Software Foundation. This program is distributed
** in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
** even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
** PURPOSE.  See the GNU General Public License for more details. You should
** have received a copy of the GNU General Public License, in a file named
** COPYING, along with this program.  If you cannot find your copy, see
** <http://www.gnu.org/licenses/gpl-3.0.html>.
*/

package com.flywheelms.library.gcg.treeview;

import java.util.ArrayList;
import java.util.Arrays;

import android.app.Activity;
import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.flywheelms.library.FmsLibraryActivity;
import com.flywheelms.library.FmsLibraryApplication;
import com.flywheelms.library.R;
import com.flywheelms.library.fmm.node.FmmNodeInfo;
import com.flywheelms.library.fmm.node.interfaces.horizontal.FmmNode;
import com.flywheelms.library.fmm.perspective.FmmPerspective;
import com.flywheelms.library.fms.helper.FmsActivityHelper;
import com.flywheelms.library.fms.miscellaneous.FmsContext;
import com.flywheelms.library.fwb.interfaces.ShowMenuActivity;
import com.flywheelms.library.gcg.treeview.node.TreeNodeInfo;

public class GcgTreeViewAdapter extends BaseAdapter {
	
    private static final String LOGGING_TAG = GcgTreeViewAdapter.class
            .getSimpleName();
    private final GcgTreeStateMediator treeStateMediator;
    private final int[] fontSizeArray;
    private final LayoutInflater layoutInflater;
    private int indentWidth = 0;
    private Drawable collapsedDrawable;
    private Drawable expandedDrawable;
    private Drawable emptyDrawable = FmsLibraryApplication.getInstance().getResources().getDrawable(R.drawable.empty_bitmap);
    private Drawable indicatorBackgroundDrawable;
    private Drawable rowBackgroundDrawable;
    private boolean collapsible;
    private final Activity activity;

    private final OnClickListener indicatorClickListener = new OnClickListener() {
    	
        @Override
        public void onClick(final View aView) {
            final TreeNodeInfo theTreeNodeInfo = (TreeNodeInfo) aView.getTag();
            expandCollapse(theTreeNodeInfo);
        }
    };

    private final OnClickListener longClickListener = new OnClickListener() {
		
		@Override
		public void onClick(View aView) {
			final TreeNodeInfo theTreeNodeInfo = (TreeNodeInfo) aView.getTag();
			launchNodeActivity(aView, theTreeNodeInfo);
		}
	};
    
    public GcgTreeViewAdapter(
    		final Activity anActivity,
    		final GcgTreeStateMediator aTreeStateMediator,
    		final int[] aFontSizeArray ) {
    	this.activity = anActivity;
    	this.treeStateMediator = aTreeStateMediator;
    	this.layoutInflater = (LayoutInflater) anActivity
    			.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    	this.fontSizeArray = aFontSizeArray;
    	this.collapsedDrawable = null;
    	this.expandedDrawable = null;
    	this.rowBackgroundDrawable = null;
    	this.indicatorBackgroundDrawable = null;
    }
    
//    private final OnCreateContextMenuListener indicatorCreateContextMenuListener = new OnCreateContextMenuListener() {
//
//		@Override
//		public void onCreateContextMenu(ContextMenu arg0, View arg1,
//				ContextMenuInfo arg2) {
//			// TODO Auto-generated method stub
//			// Expand [glyph] all children
//			// Collapse [glyph] all children
//			
//		}
//    	
//    };

    public Activity getActivity() {
        return this.activity;
    }

    protected GcgTreeStateMediator getTreeStateMediator() {
        return this.treeStateMediator;
    }

	protected void expandCollapse(final TreeNodeInfo aTreeNodeInfo) {
		if (aTreeNodeInfo.isWithChildren()) {
			if (aTreeNodeInfo.isExpanded()) {
				this.treeStateMediator.collapseChildren(aTreeNodeInfo);
			} else {
				this.treeStateMediator.expandDirectChildren(aTreeNodeInfo);
			}
		}
	}

    private void calculateNodeIndentWidth() {
        if (this.expandedDrawable != null) {
        	this.indentWidth = Math.max(getIndentWidth(),
        			this.expandedDrawable.getIntrinsicWidth());
        }
        if (this.collapsedDrawable != null) {
        	this.indentWidth = Math.max(getIndentWidth(),
        			this.collapsedDrawable.getIntrinsicWidth());
        }
    }

    @Override
    public void registerDataSetObserver(final DataSetObserver aTreeObserver) {
    	this.treeStateMediator.registerDataSetObserver(aTreeObserver);
    }

    @Override
    public void unregisterDataSetObserver(final DataSetObserver aTreeObserver) {
    	this.treeStateMediator.unregisterDataSetObserver(aTreeObserver);
    }

    @Override
    public int getCount() {
        return this.treeStateMediator.getVisibleCount();
    }

    @Override
    public Object getItem(final int aPosition) {
        return getItemId(aPosition);
    }

    public TreeNodeInfo getTreeNodeInfo(final int aPosition) {
        return this.treeStateMediator.getVisibleTreeNodeInfoList().get(aPosition);
    }

    @Override
    public boolean hasStableIds() {
        return true;
    }

    @Override
    public int getItemViewType(final int aPosition) {
        return getTreeNodeInfo(aPosition).getLevel();
    }

    @Override
    public int getViewTypeCount() {
        return this.fontSizeArray.length;
    }
    
    public int getFontSizeForLevel(int aLevel) {
    	return this.fontSizeArray[aLevel];
    }

    @Override
    public boolean isEmpty() {
        return getCount() == 0;
    }

    @Override
    public boolean areAllItemsEnabled() {
        return true;
    }

    @Override
    public boolean isEnabled(final int position) {
        return true;
    }

    @Override
    public final View getView(
    		final int aPosition,
    		final View aConvertView,
            final ViewGroup aParentViewGroup ) {
    	return getTreeNodeRow(aPosition, aConvertView);
    }
    
    public final View getTreeNodeRow(
    		final int aPosition,
    		final View aConvertView) {
        Log.d(LOGGING_TAG, "Creating a view based on " + aConvertView
                + " with position " + aPosition);
        final TreeNodeInfo theTreeNodeInfo = getTreeNodeInfo(aPosition);
        if (aConvertView == null) {
            Log.d(LOGGING_TAG, "Creating a new view");
            final LinearLayout theTreeNodeRowLayout = (LinearLayout) this.layoutInflater.inflate(
            		R.layout.tree_view__row_layout, null);
            return buildTreeNode(theTreeNodeRowLayout, getNewChildNodeView(theTreeNodeInfo),
                    theTreeNodeInfo, true);
        }
		Log.d(LOGGING_TAG, "Reusing the view");
		final LinearLayout theLinearLayout = (LinearLayout) aConvertView;
		final FrameLayout theTreeNodeTargetObjectLayout = (FrameLayout) theLinearLayout
		        .findViewById(R.id.tree_node_target_object_layout);
		final View theChildView = theTreeNodeTargetObjectLayout.getChildAt(0);
		updateNodeView(theChildView, theTreeNodeInfo);
		return buildTreeNode(theLinearLayout, theChildView, theTreeNodeInfo, false);
    }
    
	public View getNewChildNodeView(final TreeNodeInfo aTreeNodeInfo) {
        final LinearLayout theLinearLayout = (LinearLayout) getActivity()
                .getLayoutInflater().inflate(R.layout.tree_view__row_target_object_layout, null);
        return updateNodeView(theLinearLayout, aTreeNodeInfo);
    }

	public View updateNodeView(
			final View aView,
			final TreeNodeInfo aTreeNodeInfo ) {
		final ImageView theImageView =
				(ImageView)aView.findViewById(R.id.tree_node_deckangl_bitmap);
		theImageView.setPadding(getIndentWidth(aTreeNodeInfo), 0, 0, 0);
		theImageView.setImageBitmap(aTreeNodeInfo.getTargetObject().getDecKanGlBitmap());
        final TextView theTreeNodeHeadlineView =
        	(TextView) aView.findViewById(R.id.tree_node_headline);
        theTreeNodeHeadlineView.setText(aTreeNodeInfo.getTargetObject().getHeadline());
        buildNodeSummary(aTreeNodeInfo, aView);
        buildNodeQuality(aTreeNodeInfo, aView);
        if(showNodeQuality(aTreeNodeInfo) || aTreeNodeInfo.isWithChildren()) {
            setRowFillerVisible(true, aView);
        } else {
        	setRowFillerVisible(false, aView);
        }
		return aView;
	}

	private void buildNodeSummary(
			final TreeNodeInfo aTreeNodeInfo,
			final View theParentView ) {
        final TextView theNodeSummaryPrefixView =
        		(TextView) theParentView.findViewById(R.id.tree_node_summary_prefix);
        final ImageView theNodeSummaryBitmapView =
        		(ImageView)theParentView.findViewById(R.id.tree_node_summary_glyph);
        final TextView theNodeSummarySuffixView =
        		(TextView) theParentView.findViewById(R.id.tree_node_summary_suffix);
		if(showNodeSummary(aTreeNodeInfo)) {
        	theNodeSummaryPrefixView.setText(aTreeNodeInfo.getNodeSummaryPrefix());
        	theNodeSummaryBitmapView.setImageResource(aTreeNodeInfo.getNodeSummaryDrawableResourceId());
        	theNodeSummarySuffixView.setText(aTreeNodeInfo.getNodeSummarySuffix());
        } else {
        	theNodeSummaryPrefixView.setText("");
        	theNodeSummaryBitmapView.setImageResource(R.drawable.tree_view__transparent_spacer);
        	theNodeSummarySuffixView.setText("");
        }
	}

	private void buildNodeQuality(
			final TreeNodeInfo aTreeNodeInfo,
			final View aParentView ) {
		final ImageView theNodeQualityIndexImageView =
				(ImageView) aParentView.findViewById(R.id.tree_node__quality_index__glyph);
		final TextView theNodeQualityIndexTextView =
				(TextView) aParentView.findViewById(R.id.tree_node__quality_index__data);
		if(showNodeQuality(aTreeNodeInfo)) {
			int theNodeQualityIndex = aTreeNodeInfo.getTargetObject().getNodeQualityIndex();
			theNodeQualityIndexTextView.setTextColor(FmsLibraryApplication.getInstance().getResources().getColor(R.color.fms__widget_data__text_color));
			if(theNodeQualityIndex < 0) {
				theNodeQualityIndexImageView.setImageResource(R.drawable.fmm_node__quality__bad);
			} else {
				theNodeQualityIndexImageView.setImageResource(R.drawable.fmm_node__quality);
			}
			theNodeQualityIndexTextView.setText(Integer.toString(aTreeNodeInfo.getTargetObject().getNodeQualityIndex()));
		} else {
			theNodeQualityIndexImageView.setImageResource(R.drawable.tree_view__transparent_spacer);
        	theNodeQualityIndexTextView.setText("");
        }
	}

	private boolean showNodeSummary(final TreeNodeInfo aTreeNodeInfo) {
		return ((ShowMenuActivity)this.activity).isShowNodeChildSummaryForPerspective() && aTreeNodeInfo.hasNodeSummary() &&
				( aTreeNodeInfo.getLevel() + 1 >= ((ShowMenuActivity)this.activity).getShowNodeChildSummaryLevel() );
	}

	private boolean showNodeQuality(final TreeNodeInfo aTreeNodeInfo) {
		return ((ShowMenuActivity)this.activity).isShowNodeQualityForPerspective() && aTreeNodeInfo.hasNodeQuality() &&
				(aTreeNodeInfo.getLevel() + 1 >= ((ShowMenuActivity)this.activity).getShowNodeQualityLevel());
	}

    protected String getDescription(final TreeNodeInfo aTreeRowId) {
        final Integer[] hierarchy = getTreeStateMediator().getHierarchyDescription(aTreeRowId);
        return "Node " + aTreeRowId + Arrays.asList(hierarchy);
    }

    private Drawable getNodeBackgroundDrawableOrDefault(final Drawable aDrawable) {
        if (aDrawable == null) {
            return this.activity.getResources().getDrawable(R.drawable.tree_view__row_background).mutate();
        }
		return aDrawable;
    }

    public final LinearLayout buildTreeNode(
    		final LinearLayout aTreeNodeRowLayout,
            final View aChildView,
            final TreeNodeInfo aTreeNodeInfo,
            final boolean bAddChildView) {
        final Drawable theNodeBackgroundDrawable = createNodeBackgroundDrawable();
        aTreeNodeRowLayout.setBackground(
        		theNodeBackgroundDrawable == null ?
        			getNodeBackgroundDrawableOrDefault(this.rowBackgroundDrawable) :
        			theNodeBackgroundDrawable );
        final ImageView theNodeExpanderImageView =
        		(ImageView) aTreeNodeRowLayout.findViewById(R.id.tree_node_expander_image);
        theNodeExpanderImageView.setImageDrawable(getDrawable(aTreeNodeInfo));
        theNodeExpanderImageView.setBackground(
        		getNodeBackgroundDrawableOrDefault(this.indicatorBackgroundDrawable) );
        theNodeExpanderImageView.setScaleType(ScaleType.CENTER);
        theNodeExpanderImageView.setTag(aTreeNodeInfo);
        if (aTreeNodeInfo.isWithChildren() && this.collapsible) {
            theNodeExpanderImageView.setOnClickListener(this.indicatorClickListener);
//            activity.registerForContextMenu(theNodeExpanderImageView);
        } else {
            theNodeExpanderImageView.setOnClickListener(null);
        }
        aTreeNodeRowLayout.setOnClickListener(this.longClickListener);
        aTreeNodeRowLayout.setTag(aTreeNodeInfo);
        final FrameLayout theTreeNodeTargetObjectLayout = (FrameLayout) aTreeNodeRowLayout
                .findViewById(R.id.tree_node_target_object_layout);
        final FrameLayout.LayoutParams theTreeNodeFrameParams = new FrameLayout.LayoutParams(
                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        if (bAddChildView) {
            theTreeNodeTargetObjectLayout.addView(aChildView, theTreeNodeFrameParams);
        }
        theTreeNodeTargetObjectLayout.setTag(aTreeNodeInfo);
        return aTreeNodeRowLayout;
    }

    private static void setRowFillerVisible(boolean bVisible, View aTreeNodeRowLayout) {
    	View theTreeNodeFillerView = aTreeNodeRowLayout.findViewById(R.id.tree_node_filler);
    	if(bVisible) {
    		theTreeNodeFillerView.setBackgroundResource(R.color.tree_view__node_filler_line);
    	} else {
    		theTreeNodeFillerView.setBackgroundResource(R.color.perspective_tree_background);
    	}
	}

	protected int calculateIndentation(final TreeNodeInfo aTreeNodeInfo) {
        return getIndentWidth() * (aTreeNodeInfo.getLevel() + (this.collapsible ? 1 : 0));
    }

    protected Drawable getDrawable(final TreeNodeInfo aTreeNodeInfo) {
        if (!aTreeNodeInfo.isWithChildren() || !this.collapsible) {
            return this.emptyDrawable;
        }
        if (aTreeNodeInfo.isExpanded()) {
            return this.expandedDrawable;
        }
		return this.collapsedDrawable;
    }

    public void setCollapsedNodeButtonDrawable(final Drawable aCollapsedNodeButtonDrawable) {
        this.collapsedDrawable = aCollapsedNodeButtonDrawable;
        calculateNodeIndentWidth();
    }

    public void setExpandedNodeButtonDrawable(final Drawable anExpandedNodeButtonDrawable) {
        this.expandedDrawable = anExpandedNodeButtonDrawable;
        calculateNodeIndentWidth();
    }

    public void setIndentWidth(final int anIndentWidth) {
        this.indentWidth = anIndentWidth;
        calculateNodeIndentWidth();
    }

    public void setNodeRowBackgroundDrawable(final Drawable aNodeRowBackgroundDrawable) {
        this.rowBackgroundDrawable = aNodeRowBackgroundDrawable;
    }

    public void setIndicatorBackgroundDrawable(final Drawable anIndicatorBackgroundDrawable) {
        this.indicatorBackgroundDrawable = anIndicatorBackgroundDrawable;
    }

    public void setCollapsible(final boolean bCollapsible) {
        this.collapsible = bCollapsible;
    }

    public void refresh() {
    	this.treeStateMediator.refreshViews();
    }

    private int getIndentWidth() {
        return this.indentWidth;
    }

    private int getIndentWidth(TreeNodeInfo aTreeNodeInfo) {
        return (int) Math.round(this.indentWidth * aTreeNodeInfo.getLevel() * 1.7);
    }

    public void handleItemClick(final Object aNodeTargetObject) {
        expandCollapse((TreeNodeInfo) aNodeTargetObject);
    }
    
    public void handleShowNodeCompletion() {
    	this.treeStateMediator.applyTreeFilterCriteria();
    }
    
    public void handleShowCollapseToTreeLevel(int aTreeLevel) {
    	this.treeStateMediator.collapseToTreeLevel(aTreeLevel);
    }

	public Drawable createNodeBackgroundDrawable() {
		return new ColorDrawable(getActivity().getResources().getColor(R.color.perspective_tree_background));
		// to create different background colors for each/some tree levels
//		switch (treeNodeInfo.getLevel()) {
//		case 0:
//			return new ColorDrawable(Color.WHITE);
//		case 1:
//			return new ColorDrawable(Color.GRAY);
//		case 2:
//			return new ColorDrawable(Color.YELLOW);
//		default:
//			return null;
//		}
	}

	@Override
	public long getItemId(int arg0) {
		// TODO Auto-generated method stub
		return 0;
	}

	private void launchNodeActivity(View aView, TreeNodeInfo aTreeNodeInfo) {
		String theNodeClassName = aTreeNodeInfo.getTargetObject().getClass().getSimpleName();
		String theNodeIdToDisplay = ((FmmNode) aTreeNodeInfo.getTargetObject()).getNodeIdString();
		String theParentNodeId = ((FmmNode) this.treeStateMediator.getParent(aTreeNodeInfo).getTargetObject()).getNodeIdString();
		ArrayList<String> thePeerNodeIdList = getPeerNodeIdStringList(aTreeNodeInfo);
		String theParentNodeClassName = this.treeStateMediator.getParent(aTreeNodeInfo).getTargetObject().getClass().getSimpleName();
		FmsActivityHelper.startFmmNodeActivity(aView.getContext(), getFmsContext(aTreeNodeInfo), theNodeClassName, thePeerNodeIdList, theNodeIdToDisplay, theParentNodeId, theParentNodeClassName);
	}

	private FmsContext getFmsContext(TreeNodeInfo aTreeNodeInfo) {
//		FmsContext theFmsContext = ((FmsLibraryActivity)this.activity).getFmsContext().getClone();
//		theFmsContext.addContext((FmmNodeInfo) aTreeNodeInfo.getTargetObject());
//		return theFmsContext;
		return new FmsContext(FmmPerspective.STRATEGIC_PLANNING);
	}

	private ArrayList<String> getPeerNodeIdStringList(TreeNodeInfo aTreeNodeInfo) {
		ArrayList<String> thePeerNodeIdStringList = new ArrayList<String>();
		for(TreeNodeInfo theTreeNodeInfo : this.treeStateMediator.getChildren(this.treeStateMediator.getParent(aTreeNodeInfo)) ) {
			thePeerNodeIdStringList.add(((FmmNode) theTreeNodeInfo.getTargetObject()).getNodeIdString());
		}
		return thePeerNodeIdStringList;
	}

}
